package cn.hg.solon.youcan.web.monitor.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hg.solon.youcan.common.enums.BusinessType;
import cn.hg.solon.youcan.framework.web.pear.LayuiPage;
import cn.hg.solon.youcan.framework.web.admin.annotation.Logging;
import cn.hg.solon.youcan.framework.web.cache.WebCacheService;
import cn.hg.solon.youcan.framework.web.qo.PaginationQueryObject;
import cn.hg.solon.youcan.web.BaseAdminController;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.map.MapWrapper;
import org.dromara.hutool.core.text.StrValidator;
import org.dromara.hutool.core.text.escape.EscapeUtil;
import org.dromara.hutool.core.text.split.SplitUtil;
import org.dromara.hutool.db.PageResult;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.MethodType;
import org.noear.solon.core.handle.ModelAndView;
import org.noear.solon.core.handle.Result;
import org.noear.solon.validation.annotation.NotEmpty;

import java.util.ArrayList;
import java.util.List;

/**
 * @author 胡高
 */
@Controller
@Mapping("/admin/monitor/cache")
public class CacheController extends BaseAdminController {

    private static final String SERVICE_NAME = "缓存监控";

    private static String VIEW_PATH = "/admin/monitor/cache/";

    @Inject
    private WebCacheService cacheService;

    @Mapping(path = "clearCacheAll", method = MethodType.DELETE)
    @Logging(title = SERVICE_NAME, businessType = BusinessType.CLEAR)
    @SaCheckPermission(value = {"monitor:cache:clear"})
    public Result<?> clearCacheAll(Context ctx) {
        this.cacheService.clearAll();

        return Result.succeed();
    }

    @Mapping(path = "clearCacheKeys", method = MethodType.DELETE)
    @Logging(title = SERVICE_NAME, businessType = BusinessType.DELETE)
    @SaCheckPermission(value = {"monitor:cache:del"})
    public Result<?> clearCacheKeys(Context ctx, @NotEmpty String cacheTag, @NotEmpty String ids) {
        List<String> splitKeys = SplitUtil.split(ids, ",");
        List<String> keys = new ArrayList<>(splitKeys.size());
        splitKeys.stream().forEach(item -> {
            if (StrValidator.isBlank(item)) {
                return;
            }

            keys.add(EscapeUtil.unescape(item));
        });

        this.cacheService.removeByKeys(cacheTag, ArrayUtil.ofArray(keys, String.class));

        return Result.succeed();
    }

    @Mapping(path = "clearCacheTags", method = MethodType.DELETE)
    @Logging(title = SERVICE_NAME, businessType = BusinessType.DELETE)
    @SaCheckPermission(value = {"monitor:cache:del"})
    public Result<?> clearCacheTags(Context ctx, @NotEmpty String ids) {
        List<String> splitTags = SplitUtil.split(ids, ",");
        List<String> names = new ArrayList<>(splitTags.size());
        splitTags.stream().forEach(item -> {
            if (StrValidator.isBlank(item)) {
                return;
            }

            names.add(EscapeUtil.unescape(item));
        });

        this.cacheService.removeByTags(ArrayUtil.ofArray(names, String.class));

        return Result.succeed();
    }

    @Mapping(path = "", method = MethodType.GET)
    @SaCheckLogin
    public ModelAndView index(Context ctx) {
        this.log.info("跳转到[{}]主页面", SERVICE_NAME);

        ModelAndView mav = new ModelAndView(VIEW_PATH + "index.html");

        return mav;
    }

    @Mapping(path = "queryCacheKeys", method = MethodType.POST)
    @SaCheckLogin
    public LayuiPage<MapWrapper<String, String>> queryCacheKeys(Context ctx, PaginationQueryObject page,
                                                                @NotEmpty String cacheTag) {
        PageResult<String> cacheKeyPage = this.cacheService.getKeysPage(page.getPageNumber(), page.getPageSize(), cacheTag, page.getWord());

        List<MapWrapper<String, String>> cacheKeyList = new ArrayList<>();

        cacheKeyPage.stream().forEach(item -> {
            MapWrapper<String, String> map = new MapWrapper<>(MapUtil.of("key", item));
            // 做escape转换，用于规避特殊字符
            map.put("escapeKey", EscapeUtil.escape(item));
            cacheKeyList.add(map);
        });

        LayuiPage<MapWrapper<String, String>> layuiPage = new LayuiPage<>(cacheKeyList);
        layuiPage.setCount(cacheKeyPage.getTotal());

        return layuiPage;
    }

    @Mapping(path = "queryCacheTags", method = MethodType.POST)
    @SaCheckLogin
    public LayuiPage<MapWrapper<String, String>> queryCacheTags(Context ctx, PaginationQueryObject page) {
        PageResult<String> cacheTagPage = this.cacheService.getTagsPage(page.getPageNumber(), page.getPageSize(), page.getWord());

        List<MapWrapper<String, String>> cacheTagsList = new ArrayList<>();
        cacheTagPage.stream().forEach(item -> {
            MapWrapper<String, String> map = new MapWrapper<>(MapUtil.of("name", item));
            // 做escape转换，用于规避特殊字符
            map.put("escapeTag", EscapeUtil.escape(item));
            cacheTagsList.add(map);
        });

        LayuiPage<MapWrapper<String, String>> layuiPage = new LayuiPage<>(cacheTagsList);
        layuiPage.setCount(cacheTagPage.getTotal());

        return layuiPage;
    }

    @Mapping(path = "queryCacheValue", method = MethodType.POST)
    @SaCheckLogin
    public Result<?> queryCacheValue(Context ctx, @NotEmpty String cacheTag, @NotEmpty String cacheKey) {
        Object value = this.cacheService.getValue(cacheTag, cacheKey);

        Result<Object> result = Result.succeed();

        long ttl = this.cacheService.ttl(cacheTag, cacheKey);

        result.setData(MapUtil.ofKvs(false, "value", value, "ttl", ttl));

        return result;
    }

}
